#include "Mesh.h"

Mesh::Mesh(bool bIsKilledAfterUnUse)
: Resource(bIsKilledAfterUnUse),
m_Vertices(0), m_iVertices(0), m_VBO(0),
m_Indices(0), m_iIndices(0), m_IBO(0)
{

}

Mesh::~Mesh()
{
	if (m_bIsLoaded)
	{
		glDeleteBuffers(1, &m_VBO);
		if (m_iIndices != 0)
		{
			glDeleteBuffers(1, &m_IBO);
		}

		SAFE_DEL_ARRAY(m_Vertices);
		SAFE_DEL_ARRAY(m_Indices);
	}
	printf("Mesh\n");
}

GLint Mesh::Init(char* strFileModel, char* strFileType)
{
	return 0;
}

GLint Mesh::Init(GLuint iVertices, Vertex* Vertices, GLuint iIndices, GLushort* Indices)
{
	m_iVertices = iVertices;
	m_Vertices = new Vertex[m_iVertices];
	memset(m_Vertices, 0, m_iVertices*sizeof(Vertex));
	memcpy(m_Vertices, Vertices, m_iVertices*sizeof(Vertex));

	if (iIndices > 0)
	{
		m_iIndices = iIndices;
		m_Indices = new GLushort[m_iIndices];
		memset(m_Indices, 0, m_iIndices*sizeof(GLushort));
		memcpy(m_Indices, Indices, m_iIndices*sizeof(GLushort));
	}
	return 0;
}

void Mesh::Load()
{
	if (!m_bIsLoaded)
	{
		glGenBuffers(1, &m_VBO);
		glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
		glBufferData(GL_ARRAY_BUFFER, m_iVertices*sizeof(Vertex), m_Vertices, GL_STATIC_DRAW);
		glBindBuffer(GL_ARRAY_BUFFER, 0);

		if (m_iIndices > 0)
		{
			glGenBuffers(1, &m_IBO);
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
			glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_iIndices*sizeof(GLushort), m_Indices, GL_STATIC_DRAW);
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
		}
		m_bIsLoaded = true;
	}
}

//===================================== ALL Method flollow can move into model class if you want
void Mesh::Render(const Shader* sha)
{
	//Vertices buffer
	glBindBuffer(GL_ARRAY_BUFFER, m_VBO);

	//Vertex position
	if (sha->a_VertextPos != -1)
	{
		glEnableVertexAttribArray(sha->a_VertextPos);
		glVertexAttribPointer(sha->a_VertextPos, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (char*)0);
	}
	//Vertex uv
	if (sha->a_VertTexCoord != -1)
	{
		glEnableVertexAttribArray(sha->a_VertTexCoord);
		glVertexAttribPointer(sha->a_VertTexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (char*)0 + sizeof(Vector3));
	}
	//Vertex normal
	if (sha->a_VertBiNorm != -1)
	{
		glEnableVertexAttribArray(sha->a_VertBiNorm);
		glVertexAttribPointer(sha->a_VertBiNorm, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (char*)0 + sizeof(Vector3)+sizeof(Vector2));
	}
	//Vertex binormal
	if (sha->a_VertBiNorm != -1)
	{
		glEnableVertexAttribArray(sha->a_VertBiNorm);
		glVertexAttribPointer(sha->a_VertBiNorm, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (char*)0 + sizeof(Vector3)* 2 + sizeof(Vector2));
	}
	//Vertex tangent
	if (sha->a_VertTangent != -1)
	{
		glEnableVertexAttribArray(sha->a_VertTangent);
		glVertexAttribPointer(sha->a_VertTangent, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (char*)0 + sizeof(Vector3)* 3 + sizeof(Vector2));
	}
	//Indices buffer
	if (m_iIndices > 0)
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
}

void Mesh::Unrender()
{
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	if (m_iIndices > 0)
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

//================================================================== End
Mesh* Mesh::Reference()
{
	if (!m_bIsLoaded)
		this->Load();
	m_iUser++;
	return this;
}

void Mesh::Dereference()
{
	if (m_iUser > 0)
		m_iUser--;
	else
	{
		glDeleteBuffers(1, &m_VBO);
		if (m_iIndices > 0)
		{
			glDeleteBuffers(1, &m_IBO);
		}
		if (m_bisKilledAfterUnUse)
		{
			SAFE_DEL_ARRAY(m_Vertices);
			SAFE_DEL_ARRAY(m_Indices);
		}
		m_bIsLoaded = false;
	}
}